package cim3d;

import com.sun.opengl.util.BufferUtil;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import java.awt.event.*;
import java.nio.IntBuffer;

/**
 * Created by IntelliJ IDEA.
 *
 * @author Dong Shufeng
 *         Date: 2009-10-24
 */
public class DefaultMouseListener implements MouseWheelListener, MouseListener, MouseMotionListener, GLEventListener {
    private static final int ACTION_DOUBLE_CLICK = 0;
    //private static final int ACTION_DRAGGER = 0;
    //private static final int ACTION_DOUBLE_CLICK = 0;
    //private static final int ACTION_DOUBLE_CLICK = 0;
    GraphDisplayer displayer;
    GLSelectionListener selectionListener;

    double mouseX;
    double mouseY;
    int mouseActionFlag = -1;

    public DefaultMouseListener() {
    }

    public DefaultMouseListener(GraphDisplayer gl) {
        this();
        this.displayer = gl;
    }

    public void mouseWheelMoved(MouseWheelEvent e) {
        if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
            ViewerData3D viewerData = displayer.getViewerData();
            if(viewerData != null)
                viewerData.setZp(viewerData.getZp() + e.getUnitsToScroll() * viewerData.getMove());
        }
    }

    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 2) {
            mouseActionFlag = ACTION_DOUBLE_CLICK;
        }
    }

    public void mousePressed(MouseEvent e) {
        mouseX = e.getPoint().getX();
        mouseY = e.getPoint().getY();
    }

    public void mouseReleased(MouseEvent e) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void mouseEntered(MouseEvent e) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void mouseExited(MouseEvent e) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void mouseDragged(MouseEvent e) {
        if (displayer == null)
            return;
        ViewerData3D viewerData = displayer.getViewerData();
        if(viewerData == null)
            return;
        viewerData.setXp(viewerData.getXp() + ((-e.getX() + mouseX) * viewerData.getZp() * 2.0 / viewerData.getWindowHeight()));
        viewerData.setYp(viewerData.getYp() + ((e.getY() - mouseY) * viewerData.getZp() * 2.0 / viewerData.getWindowHeight()));
        mouseX = e.getPoint().getX();
        mouseY = e.getPoint().getY();
    }

    public void mouseMoved(MouseEvent e) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void init(GLAutoDrawable glAutoDrawable) {
    }

    public void display(GLAutoDrawable drawable) {
        if (displayer == null)
            return;
        switch (mouseActionFlag) {
            case ACTION_DOUBLE_CLICK:
                ViewerData3D viewerData = displayer.getViewerData();
                if(viewerData == null)
                    return;
                GL gl = drawable.getGL();
                IntBuffer selectBuf = BufferUtil.newIntBuffer(512);
                int[] viewport = new int[4];
                int hits;

                gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
                gl.glSelectBuffer(512, selectBuf);
                gl.glRenderMode(GL.GL_SELECT);

                gl.glInitNames();

                gl.glPushMatrix();
                gl.glMatrixMode(GL.GL_PROJECTION);
                gl.glPushMatrix();
                gl.glLoadIdentity();
                GLU glu = new GLU();
                glu.gluPickMatrix(mouseX, viewport[3] - mouseY, 3.0, 3.0, viewport, 0);
                glu.gluPerspective(90, displayer.getViewerData().windowWidth / displayer.getViewerData().windowHeight, 1, 10000);

                gl.glMatrixMode(GL.GL_MODELVIEW);
                glu.gluLookAt(viewerData.getXp(), viewerData.getYp(), viewerData.getZp(), viewerData.getXp(),
                        viewerData.getYp(),viewerData.getZp() - 100, 0.0, 1.0, 0.0);
                gl.glRotated(viewerData.getXrot(), 1, 0, 0);
                gl.glRotated(viewerData.getZrot(), 0, 0, 1);
                gl.glTranslated(-displayer.getViewerData().getWindowWidth() / 2.0, displayer.getViewerData().getWindowHeight() / 2.0, 0);

                gl.glMatrixMode(GL.GL_PROJECTION);
                drawable.swapBuffers();
                displayer.drawGraphLayers(gl);
                hits = gl.glRenderMode(GL.GL_RENDER);
                gl.glPopMatrix();
                gl.glMatrixMode(GL.GL_MODELVIEW);
                gl.glPopMatrix();
                if (hits > 0 && selectionListener != null) {
                    System.out.println("========" + selectBuf.get(3));
                    selectionListener.processHits(hits, selectBuf, 0);//todo:
                }
                mouseActionFlag = -1;
                break;
            default:
                break;
        }
    }

    public void reshape(GLAutoDrawable glAutoDrawable, int i, int i1, int i2, int i3) {
    }

    public void displayChanged(GLAutoDrawable glAutoDrawable, boolean b, boolean b1) {
    }


    public GraphDisplayer getDisplayer() {
        return displayer;
    }

    public void setDisplayer(GraphDisplayer displayer) {
        this.displayer = displayer;
    }

    public GLSelectionListener getSelectionListener() {
        return selectionListener;
    }

    public void setSelectionListener(GLSelectionListener selectionListener) {
        this.selectionListener = selectionListener;
    }
}
